package org.lex.swing.widgets;

import java.awt.BorderLayout;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.RowFilter;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableRowSorter;

public class CharsetPane extends JPanel {
	private JTable table = null;
	private CharsetTableModel tableModel = null;
	private TableRowSorter<CharsetTableModel> sorter = null;

	public CharsetPane() {
		super();
		initialize();
	}

	public void setSelectionMode(int selectionMode) {
		getTable().setSelectionMode(selectionMode);
	}

	@SuppressWarnings("unchecked")
	public void setFilter(RowFilter filter) {
		this.getSorter().setRowFilter(filter);
	}

	// =================================
	public Charset getSelectedCharset() {
		int row = this.getTable().getSelectedRow();
		if (-1 == row)
			return null;
		row = this.getTable().convertRowIndexToModel(row);
		return this.getTableModel().getCharset(row);
	}

	public Charset[] getSelectedCharsets() {
		return this.getTableModel().getCharsets(this.getSelectedRowsInModel());
	}

	protected int[] getSelectedRowsInModel() {
		int[] rows = this.getTable().getSelectedRows();
		for (int i = 0; i < rows.length; i++)
			rows[i] = table.convertRowIndexToModel(rows[i]);
		return rows;
	}

	protected JTable getTable() {
		if (table == null) {
			table = new JTable();
			table.setModel(this.getTableModel());
			table.setRowSorter(this.getSorter());
			table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
			int[] widths = { 125, 70, 360 };
			TableColumnModel model = table.getColumnModel();
			for (int i = 0; i < widths.length; i++)
				model.getColumn(i).setPreferredWidth(widths[i]);
		}
		return table;
	}

	protected CharsetTableModel getTableModel() {
		if (null == tableModel) {
			tableModel = new CharsetTableModel();
		}
		return tableModel;
	}

	private TableRowSorter<CharsetTableModel> getSorter() {
		if (null == sorter)
			sorter = new TableRowSorter<CharsetTableModel>(getTableModel());
		return this.sorter;
	}

	// =======================
	private void initialize() {
		this.setSize(300, 200);
		this.setLayout(new BorderLayout());
		JScrollPane scroll = new JScrollPane();
		scroll.setViewportView(getTable());
		this.add(scroll, BorderLayout.CENTER);
	}

	private static String[] columnName = { "Name", "Can Encode", "Aliases" };

	class CharsetTableModel extends AbstractTableModel {
		private List<Entry> data = null;
		private List<Charset> charsets = null;

		public CharsetTableModel() {
			super();
			this.loadCharsets();
		}

		public String getName(int row) {
			return this.data.get(row).name;
		}

		public String[] getNames(int[] rows) {
			String[] names = new String[rows.length];
			for (int i = 0; i < rows.length; i++)
				names[i] = this.data.get(rows[i]).name;
			return names;
		}

		public Charset getCharset(int row) {
			return this.charsets.get(row);
		}

		public Charset[] getCharsets(int[] rows) {
			Charset[] cs = new Charset[rows.length];
			for (int i = 0; i < rows.length; i++)
				cs[i] = this.charsets.get(rows[i]);
			return cs;
		}

		public String getColumnName(int column) {
			return columnName[column];
		}

		public Class<?> getColumnClass(int column) {
			if (1 == column)
				return Boolean.class;
			return super.getColumnClass(column);
		}

		public int getColumnCount() {
			return columnName.length;
		}

		public int getRowCount() {
			return data.size();
		}

		public Object getValueAt(int row, int column) {
			Entry entry = data.get(row);
			switch (column) {
			case 0:
				return entry.name;
			case 1:
				return entry.canEncode;
			case 2:
				return entry.alias;
			}
			return null;
		}

		private void loadCharsets() {
			Map<String, Charset> all = Charset.availableCharsets();
			Set<String> names = all.keySet();
			this.data = new ArrayList<Entry>(names.size());
			this.charsets = new ArrayList<Charset>(names.size());
			for (String name : names)
				this.charsets.add(all.get(name));
			Collections.sort(this.charsets);
			Iterator<Charset> itor = this.charsets.iterator();
			while (itor.hasNext())
				this.data.add(new Entry(itor.next()));
		}

		class Entry implements Comparable<Entry> {
			public String name = "";
			public boolean canEncode = false;
			public String alias = "";

			Entry(Charset charset) {
				super();
				this.name = charset.name();
				this.canEncode = charset.canEncode();
				this.alias = String.valueOf(charset.aliases());
			}

			public int compareTo(org.lex.swing.widgets.CharsetPane.CharsetTableModel.Entry o) {
				return this.name.compareTo(o.name);
			}
		}
	}
}
